package com.miyake.dsp.ui;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import com.miyake.dsp.DspComposite;
import com.miyake.dsp.circuit.RcSetting;
import com.miyake.dsp.converter.InvertSetting;
import com.miyake.dsp.converter.LimiterSetting;
import com.miyake.dsp.converter.LogSetting;
import com.miyake.dsp.converter.MovingAverageSetting;
import com.miyake.dsp.converter.OffsetSetting;
import com.miyake.dsp.file.CompositePersistent;
import com.miyake.dsp.file.CompositePersistentImplXml;
import com.miyake.dsp.filter.FilterSetting;
import com.miyake.dsp.filter.FilterSetting.FilterAlgo;
import com.miyake.dsp.filter.FilterSetting.FilterType;
import com.miyake.dsp.generator.NoiseSetting;
import com.miyake.dsp.generator.PulseSetting;
import com.miyake.dsp.otdr.OtdrSetting;
import com.miyake.dsp.ui.DspCompositeUI.DspCompositeUiHandler;
import com.miyake.dsp.ui.DspCompositeUiFactory.Engine;

public class DspEditor extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = -5765391324252640626L;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		new DspEditor(100e6, true).setVisible(true);
	}

	private JPanel canvas;
	private DspCompositeUiFactory factory;
	
	private final String pulse = "Pulse Generator";
	private final String noise = "Noise Generator";
	private final String filter = "Filter";
	private final String otdr = "OTDR";
	private final String absolute = "Absolute";
	private final String normalize = "Normalize";
	private final String log = "Log";
	private final String limiter = "Limiter";
	private final String rc = "RC";
	private final String invert = "Invert";
	private final String offset = "Offset";
	private final String moveingAverage = "Moving Average";
	
//	private final double defaultFrequency = 1000e6;

	private DspCompositeUI entryPoint;
	private JComboBox combo;
	private FlowPersistence flowPersist;
	private String filename = "sequence.xml";
	
	private double defaultFrequency;
	public DspEditor (double frequency, boolean standalone) {
		defaultFrequency = frequency;
		this.setSize(600, 600);
		this.getContentPane().setLayout(null);
		this.getContentPane().add(createEngine());
		this.getContentPane().add(createFrequency());
//		this.getContentPane().add(createAddItem());
		this.getContentPane().add(createSave());
		this.getContentPane().add(createCanvas());
		
		factory = new DspCompositeUiFactory(frequency);
		
		flowPersist = new FlowPersistenceImplXml();
		
		if (standalone) {
			createDefaultComposite();
		}
	}
	
	public DspCompositeUI getEntryPoint() {
		return entryPoint;
	}

	public void setEntryPoint(DspCompositeUI entryPoint) {
		this.entryPoint = entryPoint;
		entryPoint.layout(canvas, 0, 0);
		DspCompositeUI current = entryPoint;
		while(true) {
			current.addUiHandler(new DspCompositeUiHandler() {
				@Override
				public void onAdd(DspCompositeUI ui) {
					addComponent(ui);
				}
			});
			if (current.getComposite().getList().size() == 0) {
				break;
			}
			else {
				DspComposite c = current.getComposite().getList().get(0);	
				current = (DspCompositeUI)c.getUserObject();
			}
		}
	}

	protected void trialSave() {
		CompositePersistent c = new CompositePersistentImplXml();
		c.save("trial.xml", this.entryPoint.getComposite(), factory.getFactory());
	}

	private Component createSave() {
		JButton saveButton = new JButton("Save");
		saveButton.setBounds(500, 0, 70, 25);
		saveButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				saveFlow();
			}	
		});
		return saveButton;
	}


	protected void saveFlow() {
		flowPersist.save(filename, entryPoint, factory);
	}

	private void createDefaultComposite() {
		if (new File(filename).exists()) {
			loadFile();
		}
		else {
			entryPoint = factory.createPulseGenerator(new PulseSetting(1e-7, 1.0));
			entryPoint.addUiHandler(new DspCompositeUiHandler() {
				@Override
				public void onAdd(DspCompositeUI ui) {
					addComponent(ui);
				}
			});
		}
		
		entryPoint.layout(canvas, 0, 0);
	}

	private void loadFile() {
		entryPoint = flowPersist.load(filename);
		DspComposite c = entryPoint.getComposite();
		while(true) {
			DspCompositeUI ui = (DspCompositeUI) c.getUserObject();
			ui.addUiHandler(new DspCompositeUiHandler() {
				@Override
				public void onAdd(DspCompositeUI ui) {
					addComponent(ui);
				}
			});
			if (c.getList().size() == 0) {
				break;
			}
			c = c.getList().get(0);
		}
		entryPoint.run();
	}
	
	private JPanel createCanvas() {
		canvas = new JPanel();
		canvas.setLayout(null);
		JLabel label = new JLabel("Canvas");
		canvas.add(label, 0, 0);
		canvas.setBounds(0, 50, this.getWidth(), this.getHeight());
		
		return canvas;
	}

	private JPanel createEngine() {
		JPanel panel = new JPanel();
		panel.setBounds(200, 0, 300, 40);
		final JComboBox engine = new JComboBox();
		engine.addItem("Scilab");
		engine.addItem("Octave");
		engine.addItem("Optimized");
		panel.add(engine);
		engine.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				if (engine.getSelectedItem().equals("Scilab")) {
					factory.setEngine(Engine.Scilab);
				}
				else if (engine.getSelectedItem().equals("Octave")) {
					factory.setEngine(Engine.Octave);
				}
				else if (engine.getSelectedItem().equals("Optimized")) {
					factory.setEngine(Engine.Octave);
				}
			}
		});
		return panel;
	}
	
	private JPanel createFrequency() {
		JPanel panel = new JPanel();
		JLabel label = new JLabel("Frequency");
		panel.add(label);
		final JTextField text = new JTextField(String.valueOf(defaultFrequency));
		panel.add(text);
		
		JButton button = new JButton("Set");
		button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				factory.setFrequency(Double.valueOf(text.getText()));
			}
		});
		panel.add(button);
		panel.setBounds(0, 0, 200, 40);
		
		return panel;
	}

	protected void addComponent(final DspCompositeUI composite) {
		DspCompositeUiChooser dlg = new DspCompositeUiChooser();
		List<String> list = new ArrayList<String>();
		list.add(noise);
		list.add(filter);
		list.add(otdr);
		list.add(normalize);
		list.add(absolute);
		list.add(log);
		list.add(limiter);
		list.add(rc);
		list.add(invert);
		list.add(offset);
		list.add(moveingAverage);
		dlg.setItems(list);
		dlg.setModal(true);
		dlg.setVisible(true);
		
		String selectedItem = dlg.getSelectedItem();
		DspCompositeUI ui = null;
		if (selectedItem.equals(pulse)) {
			ui = factory.createPulseGenerator(new PulseSetting(100e-9, 1.0));
		}
		else if (selectedItem.equals(noise)) {
			ui = factory.createNoiseGenerator(new NoiseSetting(0.001));
		}
		else if (selectedItem.equals(filter)) {
			ui = factory.createFilter(new FilterSetting(FilterAlgo.Chebyshev1, FilterType.Lowpass, 2, defaultFrequency/10));
		}
		else if (selectedItem.equals(otdr)) {
			DspCompositeUI otdr = factory.createOTDR(new OtdrSetting(1550, 20));
			ui = factory.createConvolution(otdr);
		}
		else if (selectedItem.equals(normalize)) {
			ui = factory.createNormalize();
		}
		else if (selectedItem.equals(absolute)) {
			ui = factory.createAbsolute();
		}
		else if (selectedItem.equals(log)) {
			ui = factory.createLog(new LogSetting(10, -70));
		}
		else if (selectedItem.equals(limiter)) {
			ui = factory.createLimiter(new LimiterSetting(0, 10));
		}
		else if (selectedItem.equals(rc)) {
			ui = factory.createRC(new RcSetting(10, 1e-6));	
		}
		else if (selectedItem.equals(invert)) {
			ui = factory.createInvert(new InvertSetting());
		}
		else if (selectedItem.equals(offset)) {
			ui = factory.createOffset(new OffsetSetting(0.1));
		}
		else if (selectedItem.equals(moveingAverage)) {
			ui = factory.createMovingAverage(new MovingAverageSetting(10));
		}
		ui.addUiHandler(new DspCompositeUiHandler() {
			@Override
			public void onAdd(DspCompositeUI ui) {
				addComponent(ui);
			}
		});
		
		
		for (DspComposite c : composite.getCompositeList()) {
			DspCompositeUI childUI = (DspCompositeUI)c.getUserObject();
			ui.add(childUI);
		}
		composite.clear();
		composite.add(ui);
		
		entryPoint.layout(canvas, 0, 0);
		entryPoint.run();
		canvas.updateUI();
	}
}
